package com.codeoss.framework.view.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.codeoss.framework.context.YunContext;
import com.codeoss.framework.converter.IConverter;
import com.codeoss.framework.converter.IConverterStore;
import com.codeoss.framework.data.metadata.Column;
import com.codeoss.framework.data.metadata.Query;
import com.codeoss.framework.data.metadata.Restrictions;
import com.codeoss.framework.data.store.ITableStore;
import com.codeoss.framework.expression.Expression;
import com.codeoss.framework.expression.IScriptServiceStore;
import com.codeoss.framework.util.LookupInfo;
import com.codeoss.framework.util.StringUtils;
import com.codeoss.framework.view.clientscript.TableAddRowClientScript;
import com.codeoss.framework.view.clientscript.TableRemoveRowClientScript;
import com.codeoss.framework.view.component.Component;
import com.codeoss.framework.view.component.IDataBinding;
import com.codeoss.framework.view.component.IDataType;
import com.codeoss.framework.view.component.IFormFieldExpression;
import com.codeoss.framework.view.component.ILookup;
import com.codeoss.framework.view.component.IVarName;
import com.codeoss.framework.view.component.Page;
import com.codeoss.framework.view.component.Search;
import com.codeoss.framework.view.component.Table;
import com.codeoss.framework.view.datasource.DataSourceConfig;
import com.codeoss.framework.view.datasource.IDataSource;
import com.codeoss.framework.view.datasource.store.IDataSourceStore;
import com.codeoss.framework.view.model.SelectItem;
import com.codeoss.framework.view.pagebean.FormViewPageBean;
import com.codeoss.framework.view.pagebean.base.BaseFormViewPageBean;
import com.codeoss.framework.view.renderer.PropSerializeMap;
import com.codeoss.framework.view.service.IChartComponentService;
import com.codeoss.framework.view.service.IComponentService;
import com.codeoss.framework.view.service.ITableComponentService;
import com.codeoss.framework.view.service.IVariableService;
import com.codeoss.framework.view.service.store.IComponentServiceStore;
import com.codeoss.framework.view.util.ComponentDataUtil;
import com.codeoss.framework.view.util.DataSourceUtil;
import com.codeoss.framework.view.util.LookupUtil;
import com.codeoss.framework.view.util.PageBeanUtil;

@Service
public class TableComponentService extends ContainerService implements ITableComponentService,IChartComponentService {
	@Autowired
	private ITableStore tableStore;
	@Autowired
	private LookupUtil lookupUtil;
	@Autowired
	private IDataSourceStore dataSourceStore;
	@Autowired
	private IVariableService variableService;
	@Autowired
	private IScriptServiceStore scriptServiceStore;
	@Autowired
	private IComponentServiceStore componentServiceStore;
	@Autowired
	private IConverterStore converterStore;
	@Autowired
	private BaseFormViewPageBean baseFormViewPageBean;
	@Autowired
	private DataSourceUtil dataSourceUtil;
	@Autowired
	private ComponentDataUtil componentDataUtil;
	@Autowired
	private PageBeanUtil pageBeanUtil;
	@Override
	public void processValue(YunContext yunContext,Component component,Map<String,String> paraMap,Map<String,Object> dataMap) {
		super.processValue(yunContext, component, paraMap, dataMap);
		String sIds=paraMap.get(component.getId()+"_selectedvalue");
		if(!StringUtils.isEmpty(sIds)) {
			List<Long> idList=new ArrayList<Long>();
			String idArray[]=sIds.split(",");
			for (int i = 0; i < idArray.length; i++) {
				idList.add(Long.parseLong(idArray[i]));
			}
			yunContext.setAttribute(component.getId()+"__selectedvalue", idList);
		}
	}
	
	@Override
	public void processEvent(YunContext yunContext, Component component, String eventType) {
		// TODO Auto-generated method stub
		super.processEvent(yunContext, component, eventType);
		if ("addRowEvent".equals(eventType)) {
			TableAddRowClientScript tableNewRowClientScript = new TableAddRowClientScript();
			tableNewRowClientScript.setTableId(component.getId());

			Map<String, PropSerializeMap> data = generateAddRowInfo(yunContext, component);
			tableNewRowClientScript.setData(data);

			yunContext.addClientScript(tableNewRowClientScript);
			yunContext.setRenderCompleted(true);
		} else if ("removeRowEvent".equals(eventType)) {
			deleteRow(yunContext, component);

			TableRemoveRowClientScript tableRemoveRowClientScript = new TableRemoveRowClientScript();
			tableRemoveRowClientScript.setTableId(component.getId());

			yunContext.addClientScript(tableRemoveRowClientScript);
			//yunContext.setRenderCompleted(true);
		}else if ("paginationEvent".equals(eventType)) {
			Table tableComponent = (Table) component;
			Expression onPagination = tableComponent.getOnPagination();
			if (onPagination != null) {
				executeEventExpression(yunContext, component, onPagination,null);
			}
		}else if("changeEvent".equals(eventType)) {
			String changeComponentId=yunContext.getViewRequest().getData().get(component.getId()+"_changecomponent");
			String subEventType=yunContext.getViewRequest().getData().get(component.getId()+"_eventtype");
			if("changeEvent".equals(subEventType)) {
				yunContext.getPage().findComponentById(yunContext,changeComponentId);
				IComponentService componentService =(IComponentService)componentServiceStore.getComponentService(yunContext,yunContext.getFindComponent());
				componentService.processEvent(yunContext, yunContext.getFindComponent(),eventType);
				generateEditRowInfo(yunContext,component);
			}else if("componentValueChangeSystemEvent".equals(subEventType)) {
				yunContext.getPageBean().processComponentValueChangeSystemEvent(changeComponentId);
			}
			
		}else if("dataRefreshEvent".equals(eventType)) {
			Table tableComponent = (Table) component;
			DataSourceConfig c=yunContext.getPage().getDataSourceConfigById(tableComponent.getDataSource());
			com.codeoss.framework.data.metadata.Table table = (com.codeoss.framework.data.metadata.Table) tableStore.get(c.getTableName());
			List<IDataBinding> dataBindingList = yunContext.getPage()
					.getAttribute(FormViewPageBean.KEY_TABLE_FIELD_LIST + tableComponent.getId());
			String sPid=yunContext.getViewRequest().getData().get("pid");
			Column parentColumn=table.getParentColumn();
			IConverter converter=converterStore.getConverter(parentColumn.getDataType());
			Object pid=converter.convertStringToObject(sPid);
			Query query=new Query();
			query.add(Restrictions.eq(parentColumn.getColumnName(), pid));
			componentDataUtil.getTableComponentData(yunContext, yunContext.getPage(), tableComponent, dataBindingList, query);
		}else if("dataDeleteEvent".equals(eventType)) {
			deleteRow(yunContext, component);
			
			Table tableComponent = (Table) component;
			DataSourceConfig c=yunContext.getPage().getDataSourceConfigById(tableComponent.getDataSource());
			com.codeoss.framework.data.metadata.Table table = (com.codeoss.framework.data.metadata.Table) tableStore.get(c.getTableName());
			List<IDataBinding> dataBindingList =yunContext.getPage()
					.getAttribute(FormViewPageBean.KEY_TABLE_FIELD_LIST + tableComponent.getId());
			String sPid=yunContext.getViewRequest().getData().get("pid");
			Column parentColumn=table.getParentColumn();
			IConverter converter=converterStore.getConverter(parentColumn.getDataType());
			Object pid=converter.convertStringToObject(sPid);
			Query query=new Query();
			query.add(Restrictions.eq(parentColumn.getColumnName(), pid));
			componentDataUtil.getTableComponentData(yunContext, yunContext.getPage(), tableComponent, dataBindingList, query);
		}else if("sortEvent".equals(eventType)) {
			Table tableComponent = (Table) component;
			Expression sortExpression=tableComponent.getOnSort();
			if(sortExpression!=null) {
				executeEventExpression(yunContext, tableComponent, sortExpression, null);
			}
		}
	}

	protected void generateEditRowInfo(YunContext yunContext, Component component) {
		Table tableComponent = (Table) component;
		DataSourceConfig c=yunContext.getPage().getDataSourceConfigById(tableComponent.getDataSource());
		com.codeoss.framework.data.metadata.Table table = (com.codeoss.framework.data.metadata.Table) tableStore.get(c.getTableName());
		List<IDataBinding> dataBindingList =yunContext.getPage()
				.getAttribute(FormViewPageBean.KEY_TABLE_FIELD_LIST + tableComponent.getId());
		IDataBinding dataBinding = dataBindingList.get(0);
		for (int i = 0; i < dataBindingList.size(); i++) {
			dataBinding = dataBindingList.get(i);
			Column column = table.getColumnByColumnName(dataBinding.getDataField());
			((IDataType)dataBinding).setDataType(column.getDataType());
			if(dataBinding instanceof ILookup) {
				LookupInfo lookupInfo = ((ILookup)(dataBinding)).getLookupInfo();
				if (lookupInfo != null) {
					if(dataBinding instanceof Search) {
						Search search=(Search)dataBinding;
						Object value=variableService.getVariableValue(yunContext, search.getVarName());
						if(value==null) {
							continue;
						}
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,(Long)value);
						yunContext.setAttribute(((Component) dataBinding).getId() + "_selectItem", selectItemList);
					}else {
						List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
						yunContext.setAttribute(((Component) dataBinding).getId() + "_selectItem", selectItemList);
					}
				}
			}
			if(dataBinding instanceof IFormFieldExpression) {
				IFormFieldExpression formFieldExpression=(IFormFieldExpression)dataBinding;
				Expression readOnlyExpression=formFieldExpression.getReadOnlyExpression();
				if(readOnlyExpression!=null) {
					boolean returnValue=(boolean)scriptServiceStore.getScriptService(readOnlyExpression).eval(readOnlyExpression.getScript(), yunContext.getVarValueMap());
					yunContext.setAttribute(((Component) dataBinding).getId() + "_readonly", returnValue);
				}
			}
			Component fieldComponent=(Component)dataBinding;
			Expression visibleExpression=fieldComponent.getVisibleExpression();
			if(visibleExpression!=null) {
				boolean returnValue=(boolean)scriptServiceStore.getScriptService(visibleExpression).eval(visibleExpression.getScript(), yunContext.getVarValueMap());
				yunContext.setAttribute(((Component) dataBinding).getId() + "_visible", returnValue);
			}
		}
	}
	
	protected Map<String, PropSerializeMap> generateAddRowInfo(YunContext yunContext, Component component) {
		Table tableComponent = (Table) component;
		Map<String, PropSerializeMap> map = new HashMap<String, PropSerializeMap>();
		List<IDataBinding> dataBindingList =yunContext.getPage()
				.getAttribute(FormViewPageBean.KEY_TABLE_FIELD_LIST + tableComponent.getId());
		for (int j = 0; j < dataBindingList.size(); j++) {
			PropSerializeMap propSerializeMap = new PropSerializeMap();
			IDataBinding dataBinding = dataBindingList.get(j);
			map.put(((Component) dataBinding).getId(), propSerializeMap);
			
			if(dataBinding instanceof IFormFieldExpression) {
				Expression defaultValueExpression=((IFormFieldExpression)dataBinding).getDefaultValueExpression();
				if(defaultValueExpression!=null) {
					Object defaultValue=scriptServiceStore.getScriptService(defaultValueExpression).eval(defaultValueExpression.getScript(), null);
					propSerializeMap.put("value", defaultValue);
					variableService.setVariableValue(yunContext,((IVarName)dataBinding).getVarName(), defaultValue);
				}else {
					variableService.setVariableValue(yunContext,((IVarName)dataBinding).getVarName(), null);
					propSerializeMap.put("value", null);
				}
			}else {
				variableService.setVariableValue(yunContext,((IVarName)dataBinding).getVarName(), null);
				propSerializeMap.put("value", null);
			}
			if (dataBinding instanceof ILookup) {
				LookupInfo lookupInfo = ((ILookup) dataBinding).getLookupInfo();
				if (lookupInfo != null) {
					if (lookupInfo != null) {
						if(dataBinding instanceof Search) {
							Search search=(Search)dataBinding;
							Object value=variableService.getVariableValue(yunContext, search.getVarName());
							if(value==null) {
								continue;
							}
							List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo,(Long)value);
							if (selectItemList != null) {
								propSerializeMap.put("options", selectItemList);
							}
						}else {
							List<SelectItem> selectItemList = lookupUtil.getSelectItemList(yunContext, lookupInfo);
							if (selectItemList != null) {
								propSerializeMap.put("options", selectItemList);
							}
						}
					}
				}
			}

		}
		return map;
	}

	protected void deleteRow(YunContext yunContext, Component component) {
		String sId = yunContext.getViewRequest().getData().get("id");
		if (!StringUtils.isEmpty(sId)) {
			Table tableComponent = (Table) component;
			DataSourceConfig dataSourceConfig = dataSourceUtil.getDataSourceConfigById(yunContext.getPage(),
					tableComponent.getDataSource());
			Map<String, Object> dataMap = new HashMap<String, Object>();
			dataMap.put("id", Long.parseLong(sId));
			com.codeoss.framework.data.metadata.Table table=tableStore.get(dataSourceConfig.getTableName());
			IDataSource dataSource=dataSourceStore.getDataSource(table.getAccessType());
			dataSource.delete(yunContext, table, dataMap);
			baseFormViewPageBean.saveParentFormulaAndSummaryField();
		}
	}

	@Override
	public List<Long> getSelectedKeyValueList(YunContext yunContext, Component component) {
		// TODO Auto-generated method stub
		return yunContext.getAttribute(component.getId()+"__selectedvalue");
	}

	@Override
	public void getChartData(YunContext yunContext, Component component) {
		// TODO Auto-generated method stub
		Page page=yunContext.getPage();
		Table tableComponent = (Table) component;
		Query query = new Query();
		if (tableComponent.isPageable()) {
			query.setLimit(tableComponent.getPageSize());
		}
		query.setPage(1);
		List<IDataBinding> tableFieldList = new ArrayList<IDataBinding>();
		pageBeanUtil.getDataBindingList(tableComponent, tableFieldList);
		componentDataUtil.getTableComponentData(yunContext, page, tableComponent, tableFieldList, query);
	}
}
